#include "tst_waypointlist.h"
using namespace FsxWsTest;

//
// Testing the waypoint list
//
TestWaypointList::TestWaypointList()
{
    // code
}

//
// Test
//
void TestWaypointList::testWaypointFillWithTimeFrame()
{
    // expect one due to "long timeframe"
    WaypointList wl = TestWaypointList::fillWaypoints(1000);
    QVERIFY2(wl.count() == 1, "Failure, expect only one element due to timeframe");
}

//
// Test
//
void TestWaypointList::testWaypointFillWithoutTimeframe()
{
    // expect all elements, if count()>TESTWPLISTCOUNT,
    // check min update time WPTIMEFRAMEMIN
    WaypointList wl = TestWaypointList::fillWaypoints(-1);
    QVERIFY2(wl.count() == TESTWPLISTCOUNT, "Failure, expect different element count");
}

//
// Test
//
void TestWaypointList::testWaypointReduceAbsolute()
{
    WaypointList wl = TestWaypointList::fillWaypoints(-1);
    const int max = 2000;
    int removed = wl.reduce(max);
    QVERIFY2(wl.count() == max, "Reduce not working");
    QVERIFY2(removed == (TESTWPLISTCOUNT -  max), "Failure, return value wrong");
}

//
// Test
//
void TestWaypointList::testWaypointReduceTimeframe()
{
    WaypointList wl = TestWaypointList::fillWaypoints(-1);
    const int deltaTime = TestWaypointList::setWaypointTimes(wl);
    const int cut = 100;
    qint64 cutThreshold = QDateTime::currentMSecsSinceEpoch()- (cut * deltaTime);
    cutThreshold -= deltaTime / 2; // compensate runtime until now, works until deltatime is not too small!
    int removed = wl.reduceToNewerOrEqual(cutThreshold);
    QVERIFY2(wl.count() == cut, "Timeframe reduce not working");
    QVERIFY2(removed == (TESTWPLISTCOUNT - cut), "Failure, return value wrong");
}

//
// test that same waypoints are correctly eliminated and
//
void TestWaypointList::testWaypointUpdateAndRemoveRedundantWaypoints()
{
    FSXAircraftInstrumentationData id;
    FSXAircraftPositionAndSpeedData ps;
    WaypointList wl;
    qint64 timeframe = WPTIMEFRAMEMIN;
    wl.updateOrAppend(id, timeframe); // initial waypoint
    QVERIFY2(wl.count() == 1, "Expect initial waypoint");
    wl.updateOrAppend(ps, timeframe); // expect update
    QVERIFY2(wl.count() == 1, "Expect update");
    QTest::qSleep(timeframe * 1.5);
    wl.updateOrAppend(ps, timeframe); // expect 2 waypoint since delta t > timeframe
    QVERIFY2(wl.count() == 2, "Expect second temp. waypoint");
    wl.updateOrAppend(id, timeframe); // now with updated data expect identical waypoint removal
    QVERIFY2(wl.count() == 1, "Expect removal of duplicated wp"); // new waypoint since duplicated
    ps.groundAltitudeM = 1000;
    wl.updateOrAppend(id, timeframe);
    QVERIFY2(wl.count() == 2, "Expect append since changed");
}

//
// Benchmark
//
void TestWaypointList::benchmarkWaypointFillWithoutTimeframe()
{
    QBENCHMARK( TestWaypointList::fillWaypoints(-1) );
}

//
// Benchmark
//
void TestWaypointList::benchmarkCreateWaypoints()
{
    // automatically generates as many iterations as needed
    QBENCHMARK{ TestWaypointList::createWaypointAndInit(); }
}

//
// Benchmark, filling waypoints and run an absolute reduce
//
void TestWaypointList::benchmarkFillAndReduceWaypoints()
{
    QBENCHMARK{ TestWaypointList::fillAndReduceWaypoints(); }
}

//
// Create a single waypoint, and init some values (pretty normal scenario to set up a waypoint)
//
void TestWaypointList::createWaypointAndInit() {
    Waypoint wp(1,2,3,4,5,6,7,8,9,false);
    FSXAircraftPositionAndSpeedData pas;
    FSXAircraftInstrumentationData id;
    wp.update(pas);
    wp.update(id);
}

//
// Fill some waypoints and reduce them
//
void TestWaypointList::fillAndReduceWaypoints() {
    WaypointList wpl = TestWaypointList::fillWaypoints(-1, 1000);
    wpl.reduce(250);
}

//
// Fill the waypoint list
//
WaypointList TestWaypointList::fillWaypoints(const qint64 timeframeMs, const int fillNumber)
{
    WaypointList waypointList;
    FSXAircraftPositionAndSpeedData pas;
    FSXAircraftInstrumentationData id;

    for (int i=0; i < fillNumber; i++) {
        pas.groundAltitudeM = i;
        pas.groundVelocityKts = i * 10;
        pas.planeAltitudeFt = i * 10;
        pas.planeLatitudeRad = i * 0.001;
        pas.planeLongitudeRad = i * 0.001;
        waypointList.updateOrAppend(pas,timeframeMs); // timeframeMs <0 always appends

        id.airspeedTrueKts = 0 * i;
        id.indicatedAltitudeFt = MathHelper::meterToFeet(pas.groundAltitudeM);
        waypointList.updateOrAppend(id, timeframeMs < 0 ? WPTIMEFRAMEMIN : timeframeMs);
    }

    return waypointList;
}

//
// Fill the waypoint list
//
qint64 TestWaypointList::setWaypointTimes(WaypointList &waypointList) {
    int count = waypointList.count();
    const qint64 deltaTimeMs = 5 *1000; // in seconds
    qint64 t = QDateTime::currentMSecsSinceEpoch() - (count * deltaTimeMs);
    for (int i=0; i< count; i++ ) {
        Waypoint w = waypointList.at(i);
        w.setTimestampUtcEpoch(t);
        t += deltaTimeMs;
        waypointList.replace(i, w);
    }
    return deltaTimeMs;
}

// Called in FsxWsTest(), QTEST_APPLESS_MAIN(TestWaypointList)
#include "moc_tst_waypointlist.cpp"
